home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / util / FaxClient.c++ < prev    next >
C/C++ Source or Header  |  1994-08-01  |  9KB  |  359 lines

  1. /*    $Header: /usr/people/sam/fax/util/RCS/FaxClient.c++,v 1.36 1994/03/09 18:46:28 sam Rel $ */
  2. /*
  3.  * Copyright (c) 1990, 1991, 1992, 1993, 1994 Sam Leffler
  4.  * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25. #include <osfcn.h>
  26. #include <pwd.h>
  27. #include <ctype.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #include <fcntl.h>
  31. #include <sys/socket.h>
  32. #include <netinet/in.h>
  33. #include <netdb.h>
  34. #include <signal.h>
  35. #include <errno.h>
  36.  
  37. #include <Dispatch/dispatcher.h>
  38.  
  39. #include "config.h"
  40. #include "FaxClient.h"
  41.  
  42. FaxClient::FaxClient()
  43. {
  44.     init();
  45. }
  46.  
  47. FaxClient::FaxClient(const fxStr& hostarg)
  48. {
  49.     init();
  50.     setupHostModem(hostarg);
  51. }
  52.  
  53. FaxClient::FaxClient(const char* hostarg)
  54. {
  55.     init();
  56.     setupHostModem(hostarg);
  57. }
  58.  
  59. void
  60. FaxClient::init()
  61. {
  62.     fd = -1;
  63.     verbose = FALSE;
  64.     running = FALSE;
  65.     prevcc = 0;
  66.     peerdied = FALSE;
  67.     version = FAX_PROTOVERS;
  68. }
  69.  
  70. FaxClient::~FaxClient()
  71. {
  72.     (void) hangupServer();
  73. }
  74.  
  75. void
  76. FaxClient::setupHostModem(const fxStr& s)
  77. {
  78.     u_int pos = s.next(0, '@');
  79.     if (pos == s.length()) {        // no @, check for host:modem
  80.     pos = s.next(0, ':');
  81.     host = s.head(pos);
  82.     if (pos == s.length())
  83.         modem = "";
  84.     else
  85.         modem = s.tail(s.length() - (pos+1));
  86.     } else {                // modem@host
  87.     modem = s.head(pos);
  88.     if (pos == s.length())
  89.         host = "";
  90.     else
  91.         host = s.tail(s.length() - (pos+1));
  92.     }
  93. }
  94.  
  95. void
  96. FaxClient::setupHostModem(const char* cp)
  97. {
  98.     setupHostModem(fxStr(cp));
  99. }
  100.  
  101. void FaxClient::startRunning()            { running = TRUE; }
  102. void FaxClient::stopRunning()            { running = FALSE; }
  103.  
  104. void FaxClient::setProtocolVersion(u_int v)    { version = v; }
  105. void FaxClient::setHost(const fxStr& hostarg)    { setupHostModem(hostarg); }
  106. void FaxClient::setHost(const char* hostarg)    { setupHostModem(hostarg); }
  107. void FaxClient::setModem(const fxStr& modemarg)    { modem = modemarg; }
  108. void FaxClient::setModem(const char* modemarg)    { modem = modemarg; }
  109. void FaxClient::setVerbose(fxBool b)        { verbose = b; }
  110.  
  111. fxBool
  112. FaxClient::setupUserIdentity()
  113. {
  114.     struct passwd* pwd = NULL;
  115.     char* name = cuserid(NULL);
  116.     if (!name) {
  117.     name = getlogin();
  118.     if (name)
  119.         pwd = getpwnam(name);
  120.     }
  121.     if (!pwd)
  122.     pwd = getpwuid(getuid());
  123.     if (!pwd) {
  124.     printError("Can not determine your user name.");
  125.     return (FALSE);
  126.     }
  127.     userName = pwd->pw_name;
  128.     if (pwd->pw_gecos && pwd->pw_gecos[0] != '\0') {
  129.     senderName = pwd->pw_gecos;
  130.     u_int l = senderName.next(0, '&');
  131.     if (l < senderName.length()) {
  132.         /*
  133.          * Do the '&' substitution and raise the
  134.          * case of the first letter of the inserted
  135.          * string (the usual convention...)
  136.          */
  137.         senderName.remove(l);
  138.         senderName.insert(userName, l);
  139.         if (islower(senderName[l]))
  140.         senderName[l] = toupper(senderName[l]);
  141.     }
  142.     senderName.resize(senderName.next(0,','));
  143.     } else
  144.     senderName = userName;
  145.     if (senderName.length() == 0) {
  146.     printError("Bad (null) user name.");
  147.     return (FALSE);
  148.     } else
  149.     return (TRUE);
  150. }
  151.  
  152. fxBool
  153. FaxClient::callServer()
  154. {
  155.     if (host.length() == 0) {        // if host not specified by -h
  156.     char* cp = getenv("FAXSERVER");
  157.     if (cp && *cp != '\0') {
  158.         if (modem != "") {        // don't clobber specified modem
  159.         fxStr m(modem);
  160.         setupHostModem(cp);
  161.         modem = m;
  162.         } else
  163.         setupHostModem(cp);
  164.     }
  165.     if (host.length() == 0)
  166.         host = "localhost";
  167.     }
  168.     struct hostent* hp = gethostbyname((char*) host);
  169.     if (!hp) {
  170.     printError("%s: Unknown host", (char*) host);
  171.     return (FALSE);
  172.     }
  173.     fd = ::socket(hp->h_addrtype, SOCK_STREAM, 0);
  174.     if (fd < 0) {
  175.     printError("Can not create socket to connect to server.");
  176.     return (FALSE);
  177.     }
  178.     struct sockaddr_in sin;
  179.     memset(&sin, 0, sizeof (sin));
  180.     sin.sin_family = hp->h_addrtype;
  181.     struct servent* sp = getservbyname("fax", "tcp");
  182.     if (sp) {
  183.     sin.sin_port = sp->s_port;
  184.     for (char** cpp = hp->h_addr_list; *cpp; cpp++) {
  185.         memcpy(&sin.sin_addr, *cpp, hp->h_length);
  186.         if (::connect(fd, (struct sockaddr*) &sin, sizeof (sin)) >= 0) {
  187.         fdOut = fd;
  188.         signal(SIGPIPE, fxSIGHANDLER(SIG_IGN));
  189.         Dispatcher::instance().link(fd, Dispatcher::ReadMask, this);
  190.         if (version > 0) {
  191.             sendLine("version", version);
  192.             if (modem != "")
  193.             sendLine("modem", modem);
  194.             if (userName == "")
  195.             setupUserIdentity();
  196.             sendLine("userID", userName);
  197.         }
  198.         return (TRUE);
  199.         }
  200.     }
  201.     printError("Can not reach \"fax\" service at host \"%s\".",
  202.         (char*) host);
  203.     } else
  204.     printError("Can not find port number for \"fax\" service.");
  205.     ::close(fd), fd = -1;
  206.     return (FALSE);
  207. }
  208.  
  209. fxBool
  210. FaxClient::hangupServer()
  211. {
  212.     if (fd != -1) {
  213.     if (Dispatcher::instance().handler(fd, Dispatcher::ReadMask) == this)
  214.         Dispatcher::instance().unlink(fd);
  215.     (void) ::close(fd);
  216.     fd = -1;
  217.     }
  218.     return (TRUE);
  219. }
  220.  
  221. void
  222. FaxClient::setFds(const int in, const int out)
  223. {
  224.     fd = in;
  225.     fdOut = out;
  226. }
  227.  
  228. fxBool
  229. FaxClient::sendLine(const char* cmd, int v)
  230. {
  231.     char num[20];
  232.     sprintf(num, "%d", v);
  233.     return sendLine(cmd, num);
  234. }
  235.  
  236. fxBool
  237. FaxClient::sendLine(const char* cmd, const char* tag)
  238. {
  239.     char line[2048];
  240.     sprintf(line, "%s:%s\n", cmd, tag);
  241.     return sendLine(line);
  242. }
  243.  
  244. fxBool
  245. FaxClient::sendLine(const char* cmd, const fxStr& s)
  246. {
  247.     return sendLine(cmd, (char*) s);
  248. }
  249.  
  250. fxBool
  251. FaxClient::sendLine(const char* line)
  252. {
  253.     if (peerdied)
  254.     return (FALSE);
  255.     if (verbose)
  256.     printf("-> %s", line);
  257.     u_int l = strlen(line);
  258.     if (write(fdOut, line, l) != l) {
  259.     if (errno != EPIPE)
  260.         printError("Server write error; line was \"%s\".", line);
  261.     else if (verbose)
  262.         printf("SEND peer died.\n");
  263.     peerdied = TRUE;
  264.     return (FALSE);
  265.     } else
  266.     return (TRUE);
  267. }
  268.  
  269. fxBool
  270. FaxClient::sendData(const char* type, const char* filename)
  271. {
  272.     if (peerdied)
  273.     return (FALSE);
  274.     int tempfd = ::open(filename, O_RDONLY);
  275.     if (tempfd < 0) {
  276.     printError("%s: Can not open (sendData).", filename);
  277.     return (FALSE);
  278.     }
  279.     struct stat sb;
  280.     fstat(tempfd, &sb);
  281.     int cc = (int) sb.st_size;
  282.     if (verbose)
  283.     printf("SEND \"%s\" (%s:%d bytes)\n", filename, type, cc);
  284.     sendLine(type, cc);
  285.     while (cc > 0) {
  286.     char buf[4096];
  287.     int n = fxmin((u_int) cc, sizeof (buf));
  288.     if (read(tempfd, buf, n) != n) {
  289.         printError("Protocol botch (data read).");
  290.         return (FALSE);
  291.     }
  292. #ifdef __linux__
  293.     /*
  294.      * Linux kernel bug: can get short writes on
  295.      * stream sockets when setup for blocking i/o.
  296.      */
  297.     cc -= n;
  298.     for (int cnt, sent = 0; n; sent += cnt, n -= cnt) 
  299.         if ((cnt = write(fdOut, buf + sent, n)) <= 0) {
  300.             printError("Protocol botch (data write).");
  301.         return (FALSE);
  302.         }
  303. #else
  304.     if (write(fdOut, buf, n) != n) {
  305.         printError("Protocol botch (data write).");
  306.         return (FALSE);
  307.     }
  308.     cc -= n;
  309. #endif
  310.     }
  311.     ::close(tempfd);
  312.     return (TRUE);
  313. }
  314.  
  315. int
  316. FaxClient::inputReady(int)
  317. {
  318.     int n = ::read(fd, buf+prevcc, sizeof (buf) - prevcc - 1);
  319.     if (n > 0) {
  320.     n += prevcc;
  321.     buf[n] = '\0';
  322.     for (char *bp = buf; *bp;) {
  323.         char *cp = strchr(bp, '\n');
  324.         if (!cp) {
  325.         prevcc = n - (bp - buf);
  326.         memmove(buf, bp, prevcc);
  327.         goto done;
  328.         }
  329.         *cp++ = '\0';
  330.         if (verbose)
  331.         printf("<- %s\n", bp);
  332.         char* tag = strchr(bp, ':');
  333.         if (tag) {
  334.         *tag++ = '\0';
  335.         while (isspace(*tag))
  336.             tag++;
  337.         recvConf(bp, tag);
  338.         } else if (strcmp(bp, ".") == 0) {
  339.         recvConf(bp, "");
  340.         } else
  341.         fprintf(stderr,
  342.             "Malformed server message \"%s\" ignored.\n", bp);
  343.         bp = cp;
  344.     }
  345.     prevcc = 0;
  346.     } else if (n == 0) {
  347.     if (verbose)
  348.         printf("<- EOF\n");
  349.     recvEof();
  350.     } else {
  351.     if (verbose)
  352.         printf("<- ERROR (errno = %d)\n", errno);
  353.     if (!peerdied || errno != ECONNRESET)
  354.         recvError(errno);
  355.     }
  356. done:
  357.     return (0);
  358. }
  359.